﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace T810_CAN.CAN
{
    /// <summary>
    /// CAN_Connect接收模式
    /// </summary>
    public enum Enum_RECEIVE_MODE
    {
        RX_MODE_NOREC,
        RX_MODE_EVENT,
        RX_MODE_BUF
    }

    /// <summary>
    /// CAN硬件层封装
    /// </summary>
    public class CANalyst_II : CanBase
    {
        public Action<string> can_messageout;

        /// <summary>
        /// 接收缓冲区
        /// </summary>
        private ConcurrentQueue<CanFrame> CAN_Frame_Buffer = new ConcurrentQueue<CanFrame>();

        /// <summary>
        /// 内部接收线程
        /// </summary>
        private Thread CAN_rx_thread;

        /// <summary>
        /// 接收模式
        /// </summary>
        public Enum_RECEIVE_MODE receive_mode = Enum_RECEIVE_MODE.RX_MODE_EVENT;

        #region 事件
        public delegate void CAN_Frame_Receive(CanFrame frame);
        public event CAN_Frame_Receive CAN_Frame_Received;
        #endregion

        public CANalyst_II()
        {
            CANConfig = new CanConfig()
            {
                DeviceType = 4,
                DeviceIndex = 0,
                CANIndex = 0,
                AccCode = 0x00000000,
                AccMask = 0xFFFFFFFF,
                Filter = 0,//0或1接收所有帧
                Mode = 0,
                Timing0 = 0x00,
                Timing1 = 0x1C,
            };

            CAN_rx_thread = new Thread(thread_can_rx);
            CAN_rx_thread.IsBackground = true;
            CAN_rx_thread.Start();
        }

        ~CANalyst_II()
        {
            ControlCAN_API.VCI_CloseDevice(CANConfig.DeviceType, CANConfig.DeviceIndex);
        }

        public override void Start()
        {
            if (!this.isConnected)//设备未连接
            {
                if (!Connect_Device())//连接失败
                {
                    return;
                }
            }
            if (!this.isOpen) //未启动
            {
                Start_CAN();
            }
        }

        public override void Stop()
        {
            if (isOpen)
            {
                if (Stop_CAN())
                {
                    if (isConnected)
                    {
                        DisConnect_Device();
                    }
                }
            }
        }

        /// <summary>
        /// CAN通信的接收线程
        /// </summary>
        unsafe private void thread_can_rx()
        {
            while (true)
            {
                try
                {
                    if (this.isOpen)
                    {
                        //不安全代码，需要做临界处理
                        int res = (int)ControlCAN_API.VCI_Receive(CANConfig.DeviceType, CANConfig.DeviceIndex, CANConfig.CANIndex, ref CAN_OBJ_BUF[0], 2100, 0);
                        if (res == -1)//读取错误
                        {
                            return;
                        }

                        for (UInt32 i = 0; i < res; i++)
                        {
                            CanFrame frame = new CanFrame(CAN_OBJ_BUF[i]);
                            can_messageout?.Invoke(frame.ToString());
                            switch (receive_mode)
                            {
                                case Enum_RECEIVE_MODE.RX_MODE_NOREC:
                                    break;
                                case Enum_RECEIVE_MODE.RX_MODE_EVENT:
                                    CAN_Frame_Received?.Invoke(frame);
                                    break;
                                case Enum_RECEIVE_MODE.RX_MODE_BUF:
                                    CAN_Frame_Buffer.Enqueue(frame);
                                    break;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    //LogHelper.ERROR(e.ToString());
                }
                Thread.Sleep(1);
            }
        }

        #region CAN设备接口
        private VCI_BOARD_INFO1[] BOARD_INFO1_BUF = new VCI_BOARD_INFO1[255];//读取设备信息缓冲
        private VCI_CAN_OBJ[] CAN_OBJ_BUF = new VCI_CAN_OBJ[2100];//读取CAN帧接收缓冲

        /// <summary>
        /// 查找可用设备
        /// </summary>
        /// <returns></returns>
        public override int Find_Device()
        {
            uint ret = 0;
            try
            {
                ret = ControlCAN_API.VCI_FindUsbDevice(ref BOARD_INFO1_BUF[0]);
            }
            catch (Exception e)
            {
                Trace.WriteLine("查询CANalyst_II设备失败\r\n" + e.ToString());
                //LogHelper.ERROR("查询CANalyst_II设备失败\r\n" + e.ToString());
            }
            return (int)ret;
        }

        /// <summary>
        /// CAN连接函数
        /// 重写CAN_Base的实现
        /// </summary>
        /// <returns></returns>
        public override bool Connect_Device()
        {
            if (!isConnected)
            {
                try
                {
                    VCI_INIT_CONFIG config = new VCI_INIT_CONFIG()
                    {
                        AccCode = CANConfig.AccCode,
                        AccMask = CANConfig.AccMask,
                        Filter = (byte)CANConfig.Filter,
                        Mode = (byte)CANConfig.Mode,
                        Timing0 = (byte)CANConfig.Timing0,
                        Timing1 = (byte)CANConfig.Timing1
                    };
                    if (CANConfig.DeviceIndex < this.Find_Device())//有设备连接并且打开的设备序号存在
                    {
                        if (ControlCAN_API.VCI_OpenDevice(CANConfig.DeviceType, CANConfig.DeviceIndex, 0) == 1)//打开设备成功
                        {
                            if (ControlCAN_API.VCI_InitCAN(CANConfig.DeviceType, CANConfig.DeviceIndex, CANConfig.CANIndex, ref config) == 1)//初始化CAN通道成功
                            {
                                isConnected = true;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    //LogHelper.ERROR("连接CANalyst_II失败\r\n" + e.ToString());
                }
            }
            return isConnected;
        }

        /// <summary>
        /// CAN断开连接函数
        /// </summary>
        /// <returns></returns>
        public override bool DisConnect_Device()
        {
            try
            {
                if (ControlCAN_API.VCI_UsbDeviceReset(CANConfig.DeviceType, CANConfig.DeviceIndex, 0) > 0)
                {
                    isConnected = false;
                }
            }
            catch (Exception e)
            {
                //LogHelper.ERROR("断开CANalyst_II失败\r\n" + e.ToString());
            }
            return true;
        }

        /// <summary>
        /// 启动CAN
        /// </summary>
        /// <returns>启动的结果</returns>
        public override bool Start_CAN()
        {
            try
            {
                if (ControlCAN_API.VCI_StartCAN(CANConfig.DeviceType, CANConfig.DeviceIndex, CANConfig.CANIndex) == 1)//打开CAN通道成功
                {
                    this.isOpen = true;
                }
            }
            catch (Exception e)
            {
                //LogHelper.ERROR("启动CANalyst_II失败\r\n" + e.ToString());
            }
            return this.isOpen;
        }

        /// <summary>
        /// 停止CAN
        /// </summary>
        /// <returns></returns>
        public override bool Stop_CAN()
        {
            try
            {
                isOpen = false;
                Thread.Sleep(200);//如果不加这一句会导致can报文接收线程崩溃，原因可能是非托管代码接收can报文函数在can设备关闭后依然运行导致bug
                if (ControlCAN_API.VCI_ResetCAN(CANConfig.DeviceType, CANConfig.DeviceIndex, CANConfig.CANIndex) == 1)
                {
                    isOpen = false;
                }
            }
            catch (Exception e)
            {
                //LogHelper.ERROR("停止CANalyst_II失败\r\n" + e.ToString());
            }
            return !this.isOpen;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="frame"></param>
        /// <returns></returns>
        unsafe public override bool Transmit_Frame(CanFrame frame)
        {
            if (!this.isOpen)
                return false;

            VCI_CAN_OBJ sendobj = frame.Get_VCI_CAN_OBJ();
            int sendnum = (int)ControlCAN_API.VCI_Transmit(CANConfig.DeviceType, CANConfig.DeviceIndex, CANConfig.CANIndex, ref sendobj, 1);
            if (sendnum == 0)
            {
                //LogHelper.WARNING("CANalyst_II发送报文失败");
                return false;
            }
            can_messageout?.Invoke($"{frame.ToString()}");
            return true;
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <returns></returns>
        public override CanFrame Receive_Frame()
        {
            return null;
        }
        #endregion

    }

}
